﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace Qreed.Xna.Font
{
    public class ExtrudedFontCharacterMesh : VectorFontCharacterMesh
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ExtrudedFontCharacterMesh"/> class.
        /// </summary>
        /// <param name="font">The font.</param>
        /// <param name="vectorFontCharacter">The vector font character.</param>
        /// <param name="extrudeLength">Length of the extrude.</param>
        internal ExtrudedFontCharacterMesh(RenderFont font)
            : base(font)
        {
        }

        /// <summary>
        /// Builds the vertex buffer.
        /// </summary>
        /// <param name="copyFrom">The copy from.</param>
        /// <param name="vertices">The vertices.</param>
        /// <param name="indices">The indices.</param>
        protected override void BuildVertexBuffer(VectorFontCharacter copyFrom, out VertexPositionNormalTexture[] vertices, out short[] indices)
        {
            VertexPositionNormalTexture[] frontVertices;
            short[] frontIndices;

            FilledFontCharacterMesh.CreateFlatCharacter(copyFrom, out frontVertices, out frontIndices);

            if (frontVertices.Length > 0)
            {
                List<VertexPositionNormalTexture> vertexList = new List<VertexPositionNormalTexture>(frontVertices);
                List<short> indexList = new List<short>(frontIndices);

                // Build the back

                frontIndices = frontIndices.Reverse().ToArray();

                for (int i = 0; i < frontIndices.Length; i++)
                    frontIndices[i] += (short)frontVertices.Length;

                indexList.AddRange(frontIndices);
               
                float extrudeLength = ((ExtrudedFont)VectorFont).ExtrudeLength;

                for (int i = 0; i < frontVertices.Length; i++)
                {
                    VertexPositionNormalTexture front = vertexList[i];

                    Vector3 position = front.Position - new Vector3(0.0f, 0.0f, extrudeLength);

                    vertexList.Add(new VertexPositionNormalTexture(position, Vector3.Backward, Vector2.Zero));
                }


                foreach (VectorFontCharacterOutline outline in copyFrom.Outlines)
                {
                    List<_plane> planes = new List<_plane>();

                    for (int i = 0; i < outline.Length; i++)
                    {
                        // Create 2 planes based on every 2 vertices.

                        int index_1 = i + 1 == outline.Length ? outline.StartIndex : outline.StartIndex + i + 1;
                        int index_2 = outline.StartIndex + i;

                        Vector3 v1 = new Vector3(copyFrom.Vertices[index_1], 0.0f);
                        Vector3 v2 = new Vector3(copyFrom.Vertices[index_2], 0.0f);

                        Vector3 v3 = new Vector3(copyFrom.Vertices[index_2], -extrudeLength);
                        Vector3 v4 = new Vector3(copyFrom.Vertices[index_1], -extrudeLength);

                        planes.Add(new _plane(v1, v2, v4));
                        planes.Add(new _plane(v2, v3, v4));
                    }

                    foreach (_plane plane in planes)
                    {
                        indexList.Add((short)vertexList.Count);
                        vertexList.Add(new VertexPositionNormalTexture(plane.P1, plane.Normal, Vector2.Zero));
                        
                        indexList.Add((short)vertexList.Count);
                        vertexList.Add(new VertexPositionNormalTexture(plane.P2, plane.Normal, Vector2.Zero));

                        indexList.Add((short)vertexList.Count);
                        vertexList.Add(new VertexPositionNormalTexture(plane.P3, plane.Normal, Vector2.Zero));
                    }

                }

                vertices = vertexList.ToArray();
                indices = indexList.ToArray();
            }
            else
            {
                vertices = new VertexPositionNormalTexture[0];
                indices = new short[0];
            }
        }

        private struct _plane
        {
            public _plane(Vector3 p1, Vector3 p2, Vector3 p3)
            {
                P1 = p1; P2 = p2; P3 = p3;

                Vector3 v1 = p2 - p1;
                Vector3 v2 = p3 - p1;

                Normal = Vector3.Cross(v2, v1);
                Normal.Normalize();
            }

            public Vector3 P1;
            public Vector3 P2;
            public Vector3 P3;
            public Vector3 Normal;
        }
    }
}
